from typing import List
from fastapi import HTTPException, status, Request, Depends
from sqlalchemy.orm import Session
from table.user import User
from paramsModel.common import Page
from common.db_init import get_db
from fastapi.security import OAuth2PasswordBearer
from table.user_role import UserRole
from common.response import ApiResponse, CustomApiResponse, response_code, responseCode
from .UserRole import UserRole as UserRoleModel
from common.setting import settings
from jose import jwt, JWTError
from common.custom_log import my_logger
from utils.handle_image import makeGetFileUrl
from passlib.context import CryptContext
from datetime import datetime, timedelta, timezone
from typing import Union

oauth2_scheme = OAuth2PasswordBearer(tokenUrl=settings.TOKEN_URL, auto_error=False)
# 使用CryptContext 对象加密密码
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


class UserModel:

    # 根据名称查询是否存在该用户并返回改用户信息
    @classmethod
    def authenticate_user(cls, db: Session, form_data):
        user_dict = cls.get_user_by_name(db, form_data.username)
        if not user_dict:
            return False
        if not cls.verify_password(form_data.password, user_dict.get('hashed_password')):
            return False
        return user_dict

    @classmethod
    def create_access_token(cls, data: dict, expires_delta: Union[timedelta, None] = None):
        to_encode = data.copy()
        if expires_delta:
            expire = datetime.now(timezone.utc) + expires_delta
        else:
            expire = datetime.now(timezone.utc) + timedelta(minutes=settings.TOKEN_EXPIRE_MINUTES)
        to_encode.update({"exp": expire})
        encoded_jwt = jwt.encode(to_encode, settings.TOKEN_SECRET_KEY, algorithm=settings.TOKEN_ALGORITHM)
        return encoded_jwt

    @classmethod
    async def get_current_user(cls, request: Request, token: str = Depends(oauth2_scheme),
                               db: Session = Depends(get_db)):
        credentials_exception = HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=CustomApiResponse(message="Authorization error"),
            headers={"WWW-Authenticate": "Bearer"}
        )
        # 判断是否输入了token
        if token is None:
            credentials_exception.detail = CustomApiResponse(message="Authorization is None",
                                                             code=response_code.get('refreshToken')).dict()
            raise credentials_exception
        try:
            payload = jwt.decode(token, settings.TOKEN_SECRET_KEY, algorithms=[settings.TOKEN_ALGORITHM])
            username: str = payload.get("username")
            user_id: str = payload.get("id")
            if username is None:
                credentials_exception.detail = CustomApiResponse(message="user is null",
                                                                 code=response_code.get('refreshToken')).dict()
                raise credentials_exception
        except jwt.JWTError as e:
            my_logger.info(str(e))
            credentials_exception.detail = CustomApiResponse(message=str(e),
                                                             code=response_code.get('refreshToken')).dict()
            raise credentials_exception
        user = cls.get_user_by_id(db, id=user_id)
        if user is None:
            credentials_exception.detail = CustomApiResponse(message="user is null").dict()
            raise credentials_exception
        else:
            # 对检索出的头像路径进行组装
            user['avatar'] = '' if not user['avatar'] else makeGetFileUrl(request, query={'width': 300},
                                                                          filepath=r'/' + user.get("avatar"))
        return user

    # 根据用户传入的密码来进行重新加密并和数据库中存储的用户密码进行比对
    @classmethod
    def fake_hash_password(cls, password: str):
        return pwd_context.hash(password)

    # 验证密码是否一致
    @classmethod
    def verify_password(cls, plain_password, hashed_password):
        print(cls.fake_hash_password('123456'), hashed_password)
        return pwd_context.verify(plain_password, hashed_password)

    # 根据名称查询用户
    @classmethod
    def get_user_by_name(cls, db: Session, name: any) -> User:
        user = db.query(User).filter(User.name == name).one_or_none()
        return user.schema()

    # 根据id查询并且status不等于1的第一条用户
    @classmethod
    def get_user_by_id(cls, db: Session, id: any) -> User:
        user = db.query(User).filter(User.id == id, User.status == 0).one_or_none()
        return user.schema() if user is not None else None

    @classmethod
    def add_user(cls, db: Session, userinfo=None):
        userinfo = userinfo.model_dump(exclude_none=True)
        if userinfo['role']:
            role_id = userinfo['role']
            del userinfo['role']
        hasOne = db.query(User).filter(User.name == userinfo['name']).one_or_none()
        if hasOne:
            raise HTTPException(status_code=status.HTTP_200_OK,detail='用户名重复!')
        try:
            user = User(**userinfo)
            db.add(user)
            db.commit()
            return user.schema().get('id') if user is not None else None
        except Exception as e:
            my_logger.error(f"发生错误: {e}")
            raise HTTPException(status_code=status.HTTP_200_OK,detail='操作错误!')
            # 出错可以回滚
            # db.rollback()
            # print(str(e),'----')
            # return CustomApiResponse(code=responseCode.Error.value, message=str(e))

    # 修改用户信息
    @classmethod
    def update_user(cls, db: Session, userinfo: User = None):
        findOne = db.query(User).filter(User.id == userinfo.id).one_or_none()
        if findOne is None:
            return None
        findOne.name = userinfo.name
        db.commit()
        return True

    # 更新数据
    @classmethod
    def update_info(cls, user_id, user_name, isdel: int | str):
        Session.query(User).filter(User.id == user_id).update({User.name: user_name, User.status: isdel})
        Session.commit()

    @classmethod
    def update_userinfo(cls, db: Session, userinfo: User = None):
        if userinfo.get('avatarpath'):
            userinfo['avatar'] = userinfo.get('avatarpath')
            del userinfo['avatarpath']
        db.query(User).filter(User.id == userinfo.get('id')).update(userinfo)
        db.commit()
        db.flush()

    # 删除数据
    @classmethod
    def del_by_id(cls, id):
        del_count = Session.query(User).filter(User.id == id).delete()
        print('删除数目：', del_count)
        Session.commit()

    # 获取分页用户列表
    @classmethod
    def get_page_list(cls, db: Session, page: Page):
        userlist = db.query(User).filter(User.status == 0).offset(page['start']).limit(page['pagesize']).all()
        total = cls.get_total_users(db)
        total_pages: int = -(-total // page['pagesize']) if -(-total // page['pagesize']) is not None else 0
        return {"total": total, "total_pages": total_pages, "list": cls.formatterUsersInRole(cls, userlist)}

    def formatterUsersInRole(self, Users):
        back = []
        for item in Users:
            row = item.schema()
            row['roles'] = [{'name': getattr(user_role.role, 'name')} for user_role in item.user_role]
            back.append(row)
        return back

    # 获取用户的总数
    @classmethod
    def get_total_users(cls, db: Session):
        return db.query(User).filter(User.status == 0).count()

    # 批量删除
    @classmethod
    def del_Batch(cls, uids: List[str | int], db: Session):
        users_to_dels = db.query(User).filter(User.id.in_(uids)).all()
        for user in users_to_dels:
            # 修改存储状态不是物理删除
            user.status = 1
            # 物理删除
            # db.delete(user)
        db.commit()
